/*
Continuous Testing Toolkit
Copyright (C) 2009 Paul R. Holser, Jr.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

package org.infinitest.toolkit.filter;

import java.util.List;

import static org.infinitest.toolkit.filter.FilteringRunnerHelper.*;
import static org.infinitest.toolkit.filter.TestType.*;

import org.junit.runner.Description;
import org.junit.runner.manipulation.Filter;

public class TestTypeFilter extends Filter {
    private final Class<?> clazz;
    private final List<String> typesToMatch;

    TestTypeFilter(Class<?> clazz, List<String> testTypeProperty) {
        this.clazz = clazz;
        typesToMatch = testTypeProperty;
    }

    @Override
    public boolean shouldRun(Description description) {
        boolean shouldRunMethod = shouldRunMethod(description);
        if (!shouldRunMethod)
            System.out.println("Skipping test method " + description.getDisplayName() + ".  Allowed types: "
                + typesToMatch);
        return shouldRunMethod;
    }

    private boolean shouldRunMethod(Description description) {
        if (typesToMatch.contains(TestType.ALL.name()))
            return true;

        Type type = description.getAnnotation(Type.class);
        if (type == null)
            return shouldRunClass();
        return annotationMatch(type);
    }

    public boolean shouldRunClass() {
        return typesToMatch.contains(TestType.ALL.name()) || classAnnotationMatch();
    }

    private boolean classAnnotationMatch() {
        Type type = clazz.getAnnotation(Type.class);
        if (type == null)
            return typesToMatch.contains(UNIT.name());
        return annotationMatch(type);
    }

    private boolean annotationMatch(Type type) {
        return typesToMatch.contains(typeString(type));
    }

    private String typeString(Type type) {
        if (type.name().equals(""))
            return type.value().name();
        return type.name().trim().toUpperCase();
    }

    @Override
    public String describe() {
        return "Filters test methods based on the value of their " + Type.class.getSimpleName()
            + " annotation and the value of the aystem property [" + TEST_TYPE_PROPERTY_KEY + "].";
    }
}
